﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace DCT.Huiteng.Utility.Log
{
    /*
     配置格式
     <root>
        <!-- 日志级别，如果是空字符串或all，就所有级别都记录；如果需要过滤，则Debug,Info,Warning,Error,Fatal，用逗号隔开 -->
        <val key=""level"">all</val>
        <!-- 记录日志的根目录文件夹，如果是web支持""~/xx""的格式，支持相对路径和绝对路径 -->
        <val key=""folder"">C:\log\</val>
        <!-- 日志文件格式，支持时间格式化，默认为yyyyMMdd.log -->
        <val key=""fileFormat"">""app_""yyyyMMdd"".log""</val>
        <!-- 日志缓冲写入条数，需要大于1 --> 
        <val key=""buffer"">9</val>
     </root>
 */
    public class FileLog : StringLogSkeleton
    {
        private static string DEFAULT_FORMAT = "yyyyMMdd\".log\"";
        private ConcurrentQueue<string> queue = new ConcurrentQueue<string>();

        protected override void WriteLine(LogLevel level, string str)
        {
            //增加换行符
            str = str + Environment.NewLine;
            //写入文件
            bool writefile = false;
            int buffer = this.GetBuffer();

            //写入文件
            StringBuilder fileContent = null;

            if (buffer > 1)
            {
                //插入缓存
                queue.Enqueue(str);

                //已达到缓存缓冲上限，要写入文件
                if (queue.Count >= buffer)
                {
                    writefile = true;

                    fileContent = new StringBuilder();

                    string tmp = "";
                    while (queue.TryDequeue(out tmp))
                    {
                        fileContent.Append(tmp);
                    }
                }
            }
            else
            {
                writefile = true;
                fileContent = new StringBuilder(str);
            }

            if (writefile)
            {
                WriteToFile(fileContent.ToString(), this.GetFilePath());
            }
        }

        /// <summary>
        /// 输出所有日志
        /// </summary>
        public void Flush()
        {

            if (queue.Count > 0)
            {
                StringBuilder fileContent = new StringBuilder();

                string tmp = "";
                while (queue.TryDequeue(out tmp))
                {
                    fileContent.Append(tmp);
                }
                WriteToFile(fileContent.ToString(), this.GetFilePath());
            }
        }

        private void WriteToFile(string content, string filepath)
        {
            FileUtility.MakeSureFileExist(filepath);
            File.AppendAllText(filepath, content);
        }

        private int? cachebuffer = null;

        private int GetBuffer()
        {
            if (cachebuffer == null)
            {
                int tmp;
                string bufferInConfig = this.ConfigParser.GetVal("buffer", "1");
                if (!int.TryParse(bufferInConfig, out tmp))
                {
                    tmp = 1;
                }
                cachebuffer = tmp;
            }
            return cachebuffer.Value;
        }

        protected virtual string GetFilePath()
        {
            string folder = this.ConfigParser.GetVal("folder", "");
            folder = FileUtility.GetRealPath(folder);
            string file = DateTime.Now.ToString(this.ConfigParser.GetVal("fileFormat", DEFAULT_FORMAT));
            return Path.Combine(folder, file);
        }
    }
}
